module mculib.baremetal.tls;

version(FreeStanding){}else{
    static assert(0,"not ");
}

private{
    import mculib.baremetal;
    import mculib.baremetal.stdlib;

    //__gshared extern(C) extern void* tlsptr;
    //__gshared extern(C) extern void* __tdata_start__;
    extern(C) extern __gshared void* __tp_vma;

}


import ldc.attributes;

struct rr
{
    uint r0v;
    uint r1v;
}
__gshared rr reg;

@naked
extern(C) 
void* __aeabi_read_tp() //nothrow @nounwind @nogc 
{
    import ldc.llvmasm;

    //reg.r0v = 0x8899;


    //__asm("str r1,$0","=*m,~{r5},~{r6}",&reg.r1v);
    /*
    __asm("
        mov r2,$0;
        str r0,[r2];
    ","r",reg.r0v);
    */

    //reg.r0v = __asm!uint("mov ${0},r0","=r");
    //reg.r1v = __asm!uint("mov ${0},r1","=&r");
    //__asm!uint("str r0,[$1]","=&r,=m",reg.r0v);
    //__asm("str r1, $0","=r",reg.r1v);




    /*
        cortex-m4 单处理器
        单线程工作,无tls动作,直接返回sram地址段
    */
    /*
    return __asm!(void*)(`ldr R0,=tlsptr
                        ldr R0,[R0]`,"=r");
    */
    /*
    return __asm!(void*)(`ldr R0,=$1
                        ldr R0,[R0]`,"=r,i",&tlsptr);
    */
    // 未对多线程进行处理
    // 未实tls,直接返回tdata数据段地址
    //return tlsptr;
    /*
    return __asm!(void*)(`ldr R0,=$1
                            ldr R0,[R0]`,"=r,i",&tlsptr);
                            
                            */
    //return &tlsptr;
    //void* Mem = &__sram_loadend;
    //void* tlsMem = &__sram_loadend;

    //return (cast(void*)(&__sram_loadend))-0x04;
    return (cast(void*)&__tp_vma);
}

private
extern extern(C) __gshared void* __tls_vma;
/**
    初始化tls
    当前只预计单进程执行
*/
pragma(crt_constructor,0)
static this() @nogc
{
    import mculib.baremetal.stdlib:memcpy,memset;
    

    TlsLinkerParams tls = getTlsLinkerParams();  // 获取tls linker参数

    void* tlsMem = &__tls_vma;
    //tlsMem += 0x04;

    memset(tlsMem,0x00,tls.fullSize()); // 初始化tls内存
    memcpy(tlsMem,tls.dataLma,tls.dataSize); // 复制tdata section .tdata
    memset(tlsMem+tls.dataSize,0x00,tls.bssSize); // 初始化tbss段


}



private{
    
    extern extern(C) __gshared
    {
        //tdata
        void* __tdata_vma,__tdata_lma,__tdata_size;
        //tbss
        void* __tbss_vma,__tbss_lma,__tbss_size;

        /*
        /// tdata
        extern __gshared void* __stdata_loadaddr__;
        extern __gshared size_t __tdata_start__,__tdata_size__,__tdata_end__;
        /// tbss 段
        extern __gshared size_t __tbss_start__,__tbss_size__,__tbss_end__;
        */
    }
    
	pragma(LDC_no_typeinfo)
	{
		struct TlsLinkerParams
		{
			void* dataVma;             /// < tdata section
            void* dataLma;             /// < tdata section
			size_t dataSize;           /// < total size of TLS data
			void* bssVma;              /// < tbss section
            void* bssLma;              /// < tbss section
			size_t bssSize;            /// < total size of TLS data
			//size_t fullSize;
            @property @nogc
            size_t fullSize() const => (dataSize + bssSize);
        }
	}
	/// Get TLS data defined in linker script
	TlsLinkerParams getTlsLinkerParams() nothrow @nogc 
	{
		TlsLinkerParams param;

        param.dataLma = cast(void*)&__tdata_lma;
        param.dataVma = cast(void*)&__tdata_vma;
        param.dataSize = cast(size_t)&__tdata_size;

        param.bssLma = cast(void*)&__tbss_lma;
        param.bssVma = cast(void*)&__tbss_vma;
        param.bssSize = cast(size_t)&__tbss_size;

		return param;
	}

    enum ARM_EABI_TCB_SIZE = 8;
}

enum tlsPointerIndex = 0;